import { Controller, Logger, Post } from '@nestjs/common'
import { Action, PermissionsTo } from '@boticord/auth'
import { InjectRepository } from '@nestjs/typeorm'
import { Resource, ResourceComment } from '@boticord/resources-client'
import { Repository } from 'typeorm'
import { ResourcesService } from '../services/resources.service'
import { DiscordooSnowflake } from 'discordoo'
import MeiliSearch from 'meilisearch'
import { ConfigService } from '@nestjs/config'
import { CommentsService } from '../services/comments.service'

@Controller('reindex')
export class ReindexController {
  private meili: MeiliSearch

  constructor(
    private readonly resources: ResourcesService,
    private readonly comments: CommentsService,
    @InjectRepository(Resource) private readonly resourcesRepo: Repository<Resource>,
    @InjectRepository(ResourceComment) private readonly commentsRepo: Repository<ResourceComment>,
    private readonly config: ConfigService,
  ) {
    this.meili = new MeiliSearch({
      // WMEILISEARCH_* is parsed by us to not conflict with meilisearch config which starts with MEILI_
      host: config.getOrThrow('MEILISEARCH_HOST'),
      apiKey: config.getOrThrow('MEILI_MASTER_KEY'),
    })
  }

  private readonly logger = new Logger(ReindexController.name)

  @Post()
  @PermissionsTo(Action.Reindex, 'all')
  async reindex() {
    // очищаем индексы
    await this.meili.index('bots').deleteAllDocuments()
    await this.meili.index('servers').deleteAllDocuments()
    await this.meili.index('comments').deleteAllDocuments()

    // почему фетчим каждого бота по отдельности и реиндексим: я так хочу
    // мейли сёрч на расте, потерпит, а постгрес имба, тоже потерпит
    // всё равно этот эндпоинт вызывается в двух случаях:
    // 1. хочется поменять что-то в базе напрямую(идея кал)
    // 2. обновление мейлисёрча с удалением базы данных(редко)
    const ids = await this.resourcesRepo
      .createQueryBuilder('resource')
      .select('resource.id')
      .getMany()
      .then((resources) => resources.map((resource) => resource.id))
    const promises: Promise<boolean>[] = []

    const commentsIds = await this.commentsRepo
      .createQueryBuilder('comment')
      .select('comment.id')
      .getMany()
      .then((comments) => comments.map((comment) => comment.id))

    const reindexationID = DiscordooSnowflake.generate(0)
    this.logger.log(`Reindexation #${reindexationID} started, ${ids.length} resources to be processed.`)

    for (const id of ids) {
      promises.push(
        this.resources.indexate(id)
          .then(() => true)
          .catch((e) => {
            console.log('resource failed to index', e)
            return false
          }),
      )
    }

    for (const id of commentsIds) {
      promises.push(
        this.comments.indexate(id)
          .then(() => true)
          .catch((e) => {
            console.log('review failed to index', e)
            return false
          }),
      )
    }

    Promise.all(promises)
      .then(results => {
        const failed = results.filter(e => !e).length

        if (failed >= Math.floor(ids.length / 2)) {
          this.logger.error(`Reindexation #${reindexationID} failed with more than 50% of resources failed to reindex.`)
        }

        this.logger.log(`Reindexation #${reindexationID} finished, ${failed} resources failed to be processed.`)
      })

    return { total: ids.length + commentsIds.length }
  }
}
